home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-10-25 | 20.8 KB | 402 lines | [TEXT/MPS ] |
- /*[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]*/
- /* UMemory.p */
- /* Copyright © 1985-1990 by Apple Computer, Inc. All rights reserved. */
-
- /*
- This unit implements MacApp's memory management and segment management
- schemes.
-
- The memory management scheme works by distinguishing between "permanent"
- and "temporary" heap allocation requests. Permanent requests are
- typically used for data your application allocates: objects and
- handles. Temporary requests are used for code segments and Toolbox
- resources and data, such as WDEF's and CDEF's.
-
- Permanent memory objects are considered permanent because they
- are not purged from memory until you explicitly dispose of or free them.
- (Of course, the Macintosh Memory Manager will purge them if they're
- marked purgeable.) Permanent objects are allocated with NewPermHandle.
- This prevents the MacApp GrowZone from purging temporary objects to
- accommodate a permanent one. In MacApp, all TObjects and its descendants
- are considered permanent, and are allocated with NewPermHandle.
-
- Temporary memory objects are considered temporary because MacApp's
- GrowZone procedure may purge them from memory to satisfy a memory
- allocation request. This is true regardless of whether the object is
- marked non-purgeable, although the GrowZone procedure will not purge
- locked objects (such as code segments in use). Typically, temporary
- objects are marked non-purgeable so that MacApp's GrowZone can control
- when they are purged.
-
- MacApp reserves a specific amount of heap space for temporary objects,
- the idea being that the space reserved is large enough to handle the
- largest number of temporary objects (e.g. code and system resources)
- needed at any given time. If this amount is sufficiently large, your
- program will never fail loading a segment or system resource. This
- amount is defined by the internal variable pSzCodeReserve. You can
- retrieve its value by calling GetReserveSize. It is initially set by
- the 'seg!' and 'mem!' resources, and can be changed at run-time by
- calling SetReserveSize. The procedure BuildCodeReserve reserves the
- space by allocating the handle pCodeReserve and setting its size to
- pSzCodeReserve - (the total size of all temporary objects in memory
- [at that time]).
-
- When a temporary object is loaded into memory, the size of pCodeReserve
- is adjusted accordingly. Permanent objects can be loaded into memory
- only so long as there will still be at least pSzCodeReserve bytes
- available for temporary objects.
-
- To identify which objects in the heap are temporary, MacApp maintains
- four lists of handles. The objects identified by these handles are
- considered temporary and fall under the control of MacApp's GrowZone
- procedure. The lists are:
-
- gCodeSegs - A list of handles to all CODE resources in the application
- and system resource forks.
-
- gSysMemList - A list handles to RAM-based system resources.
- By default this list includes all PACK, LDEF, MDEF, CDEF and WDEF
- resources in the system and application resource forks. You can add
- other resources, such as fonts, by calling AddHandle.
-
- gApp1MemList, gApp2MemList - Lists of handles to application data or
- resources. MacApp initializes both lists to NIL. The difference
- between the two lists is that handles in gApp1MemList are purged
- before those in gApp2MemList. You may add your own handles to these
- lists by allocating them with NewHandle and calling AddHandle for each
- handle to be added to the list.
-
- The Macintosh Memory Manager calls MacApp's GrowZone procedure only when
- all purgeable objects have been purged from the heap and there is still
- insufficient space to satisfy a memory request. The GrowZone will
- look through the lists of temporary objects in memory, making one
- purgeable so long as there is still at least pSzCodeReserve bytes
- allocated to temporary memory (the total size of the temporary objects
- in memory and the pCodeReserve handle). The GrowZone procedure attempts
- to never allow the size of the temporary objects and reserve to fall
- below pSzCodeReserve, thereby guaranteeing that space is always avail-
- able for code segments and system resources (provided pSzCodeReserve is
- large enough to handle your application at its most memory intensive
- state).
-
- The value of pSzCodeReserve is determined at startup-time by adding up
- the size of all the segments named in the 'seg!' resources, and adding
- the first value of each of the 'mem!' resources. You can derive these
- resources by observing your program and using the MacApp debugger to
- help you determine when your application uses the largest amount of
- code and system resources. Typically, we've found that this happens
- while printing on the LaserWriter, or during initialization or term-
- ination.
-
- MacApp maintains another reserve, known as the low memory reserve.
- This is a kind of emergency reserve--when all else fails we release
- the pMemReserve handle. Its size is initially determined by the second
- number of each 'mem!' resource, and can be changed by calling
- SetReserveSize. You can retrieve its size by calling GetReserveSize.
- Internally, the low-memory reserve is allocated with the pMemReserve
- handle, and its size is stored in pSzMemReserve.
-
- The procedure InitUMemory is responsible for initially setting up the
- temporary and low-memory reserves, setting up the GrowZone procedure,
- initializing handle lists, and patching LoadSeg. It signals failure
- if the temporary reserve could not be allocated.
- */
-
- #ifndef __UMemory__
- #define __UMemory__ 0
- #endif
- #if ! __UMemory__
- #define __UMemory__ 1
-
- /* • Auto-Include the requirements for this unit's interface. */
- #ifndef __TYPES__
- #include "Types.h"
- #endif
- #ifndef __MEMORY__
- #include "Memory.h"
- #endif
- #ifndef __UPatch__
- #include "UPatch.h"
- #endif
-
- const long kGZMaxAlloc = 0x7FFFFFFF;
- const unsigned long kCode = 'CODE'; /* Resource type for code */
-
- typedef Handle AHandleList[5000]; /* A list of handles */
- typedef AHandleList *HandleListPtr; /* Preferred */
- typedef HandleListPtr *HandleListHandle; /* Preferred */
- typedef HandleListPtr PHandleList; /* Left in for compatibility (2.0) */
- typedef HandleListHandle HHandleList; /* Left in for compatibility (2.0) */
-
- typedef Boolean ABoolList[5000]; /* A list of BOOLEAN */
- typedef ABoolList *BoolListPtr;
- typedef BoolListPtr *BoolListHandle;
-
- typedef long ALongList[5000]; /* A list of LONGINT */
- typedef ALongList *LongListPtr;
- typedef LongListPtr *LongListHandle;
-
- extern pascal Size gMaxLockedRsrc; /* The maximum memory consumed by locked
- resources. See CheckRsrcUsage procedure. */
- #if qDebug
- extern pascal Boolean gMemMgtBreak; /* if TRUE, break into debugger rather than
- just report memory mgt. information */
- extern pascal Boolean gRsrcReport; /* Report resource maximums to the debugger
- window. */
- extern pascal Boolean gSegReport; /* Report segment loadings to the debugger
- window. */
- #endif
- extern pascal HandleListHandle gSysMemList; /* List of system handles used to compute
- current allocated temporary memory (all
- PACK, LDEF, MDEF, CDEF, WDEF resources).
- See ScanHandles procedure. */
- extern pascal HandleListHandle gApp1MemList, /* an application defined memlist */
- gApp2MemList; /* These start out NIL. You can create lists
- of handles and place then in either of
- these variables. (One list might be
- permanent handles in your application, and
- the other based on the current situation.)
- The values stored here should be a handle
- to a list of other handles. If you modify
- either of these lists, call CheckReserve.
- It calls BuildAllReserves to recompute the
- code and low space reserve. CheckReserve's
- result indicates whether the full code
- reserve is present. If not, then your
- program may crash because a segment (or
- defproc) can't be loaded. The handles in
- the lists should normally be resources
- that your application might require at any
- given time. All these handles will
- normally be marked non-purgeable. The
- GrowZone proc, however, can purge any of
- these handles that are not locked.*/
-
- extern pascal short gCodeRefNum; /* Reference to where to find code segements
- */
-
- extern pascal HandleListHandle gCodeSegs; /* List of all code segments */
- extern pascal BoolListHandle gIsLoadedSeg; /* Maintains a flag for each segment,
-
- indicating whether the segment
- is loaded (in the
- segment loader sense). Thereby optimizing
- UnloadAllSegments. */
- extern pascal BoolListHandle gIsResidentSeg; /* Maintains a flag for each segment,
-
- indicating whether the segment is resident
- and hence should not be unloaded (in the
- segment loader sense). */
-
- extern pascal Boolean gUnloadAllSegs; /* UnloadAllSegments doesn't unload segments
- if this flag is false. */
-
- extern pascal Ptr gGZPurgeNotify; /* If non-NIL, then this will be called
- before the Grow Zone proc purges a handle.
- The proc will be passed the actual handle.
- */
- /* These are meant to be private but are in the interface just in case. */
- extern pascal LongListHandle pSegSize; /* Maintains size of each code resource. */
-
- extern pascal Handle pCodeReserve; /* Allocates temporary (code) reserve. */
- extern pascal Handle pMemReserve; /* Allocates low memory reserve. */
- extern pascal Boolean pOKCodeReserve; /* if TRUE then we have an adequate code
- reserve; if FALSE then the application
- could crash if memory is tight */
- extern pascal Boolean pPermAllocation;
- extern pascal Boolean pReserveExists; /* TRUE if the code reserve is known to be
- fully allocated */
- #if qDebug
- extern pascal long pReserveShortfall; /* amt. that we are lacking in the code
- reserve */
- #endif
- extern pascal Size pSzCodeReserve; /* Attempt to reserve this much memory for
- the temporary (code) reserve. */
- extern pascal Size pSzMemReserve; /* Attempt to reserve this much memory for
- the low-memory reserve. */
-
- extern pascal TrapPatch pSegLoadPatch; /* patch for LoadSeg */
-
- extern pascal short pOldResFile; /* The res file reference saved across
- segloads */
- extern pascal Boolean pLoadSegCalledFromOwnApp;
- /* TRUE if calling LoadMacAppSeg from the app
- and not from a _DA_ in our own heap.
- (wheels within wheels for Pete's sake!) */
-
- extern pascal short pMaxSegNum; /* The maximum segment number */
-
- /* I N I T I A L I Z A T I O N */
-
- extern pascal void InitUMemory(void);
- /* Initializes this unit. Must be called before using this unit. The caller must be in the
- program's main segment. Sets up the gCodeSegs and gSysMemList handle lists, sets the grow
- zone, calls MaxApplZone, sets gApp1MemList and gApp2MemList to NIL, patches LoadSeg and
- allocates the temporary and low-memory reserves. Fails if unable to allocate the temporary
- reserve. */
-
- /* S E G M E N T L O A D I N G */
-
- /* DEBUGGING NOTE: You cannot set a MacApp breakpoint at any of these
- routines, because they must not call anything (eg. %_BP) that may
- require a segment load. */
-
- extern pascal short GetSegNumber(Ptr aProc);
- /* GetSegNumber returns the number of the segment in which aProc resides. */
-
- extern pascal short GetSegFromPC(long ppc);
- /* Given a pc pointer, return the segment number or 0 if not found.
- Must be a loaded code segment. */
-
- extern pascal Size GetSegSize(short segnum);
- /* GetSegSize returns the size, in bytes, of the segment whose number is segnum. */
-
- extern pascal long LoadMacAppSegment(short segnum);
- /* This function patches LoadSeg. It is called from the assembly-language routine
- AMacAppLoadSeg, which is the actual patch setup by PatchTrap. AMacAppLoadSeg saves
- registers and sets up the stack by 1) allocating space for LoadMacAppSegment's result,
-
- and 2) pushing a copy of LoadSeg's parameter onto the stack for use by LoadMacAppSegment.
- Signals failure if the segment could not be loaded. */
-
- extern pascal void LoadResidentSegments(void);
- /* Makes resident the segments whose names are included in any 'res!' resources. */
-
- extern pascal Boolean PreloadSegment(short segnum);
- /* PreloadSegment calls PreloadSegmentResource to load a segment in the resource manager
- sense and then calls the segment loader to load it in the segment loader sense. */
-
- extern pascal Boolean PreloadSegmentResource(short segnum);
- /* PreloadSegment is available to programmers who want to lock a segment at the top of the
- heap without having to call a dummy procedure in that segment. It is also useful for
- determining whether a segment can in fact be loaded before you try to execute code in it.
- PreloadSegment returns TRUE if the segment could be loaded, false otherwise. */
-
- extern pascal void SetResidentSegment(short segnum, Boolean makeResident);
- /* SetResidentSegment can be used to make a segment resident (or no longer resident); re
- sident
- segments will not be unloaded by UnloadAllSegments; if a segment is made resident, it is
- also preloaded.MacApp® automatically marks its resident segment as resident (the one
- containing the procedure CmdFromMenuItem); you probably should do UnloadAllSegments before
- making a segment resident, to ensure that it is locked at the top of the heap. */
-
- extern pascal void UnloadAllSegments(void);
- /* UnloadAllSegments unloads all segments except the blank segment or the ones marked
- resident. It is called at each iteration of the main event loop to compact memory, as well
- as other places where compacting memory is needed or desirable. */
-
- /* H A N D L E L I S T M A N A G E M E N T */
-
- extern pascal void AddHandle(Handle h, HandleListHandle toList);
- /* Adds a handle to the list of handles; does not check if the handle already exists in the
- list. Simply calls Munger to add to the front of the list. */
-
- extern pascal void AddAllRsrc(ResType rType, HandleListHandle toList);
- /* Adds all the resources of type rType to the list. Filters out all ROM resources.Calls
-
- AddHandle. */
-
- extern pascal void RemHandle(Handle h, HandleListHandle toList);
- /* Removes the handle from list. */
-
- extern pascal void ScanHandles(pascal void (*DoToHandle)(Handle h, void *DoToHandle_StaticLink),
- void *DoToHandle_StaticLink);
- /* Calls DoToHandle for each handle in the lists gCodeSegs, gSysMemList, gApp1MemList and
- gApp2MemList. This procedure assumes that DoToHandle does not compact memory. */
-
- /* M E M O R Y M A N A G E M E N T */
-
- extern pascal void BuildAllReserves(void);
- /* BuildAllReserves creates the code (temporary memory) and low space reserves. These ar
- e kept
- for use at a time when an out-of-memory condition has occurred to allow most such
- occurrances to recover smoothly by deallocating the space. */
-
- extern pascal Boolean CheckReserve(void);
- /* Checks to see if the code reserve is OK. Calls BuildAllReserves and returns true if the
- full code reserve is present. If this returns false your application may bomb because a
- segment or system resource can't be loaded. */
-
- #if qDebug
-
- extern pascal void CheckRsrcUsage(void);
- /* Checks to see if the total size of the currently loaded resources exceeds the maximum
- (gMaxLockedRsrc).If so, the new maximum is set.If gRsrcReport is true, then the new maximum
- is reported in the debugger window.If gMemMgtBreak then program execution is stopped. */
- #endif
- #if qDebug
-
- extern pascal void DoChangeReserve(Boolean alter, Size *codeReserve, Size *codeShort, Size *
- lowSpaceReserve, Boolean *gotCode, Boolean *gotLowSpace);
- /* Called by the MacApp® debugger to change the reserve allocation. Not normally called
- by an
- application. */
- #endif
-
- extern pascal void FailNoReserve(void);
- /* IF NOT CheckReserve THEN Failure(memFullErr, 0). */
-
- extern pascal void FailSpaceIsLow(void);
- /* IF MemSpaceIsLow THEN Failure(memFullErr, 0). */
-
- extern pascal void GetReserveSize(Size *szCodeReserve, Size *szMemReserve);
- /* Returns the amount of memory that is to be reserved for the code and memory reserve. This
- is not a true indication of whether this amount of memory has in fact been reserved. Call
- CheckReserve to find out if the code reserve could be allocated, and call MemSpaceIsLow to
- find out if the low-memory reserve could be allocated. */
-
- extern pascal Boolean MemSpaceIsLow(void);
- /* Returns TRUE if the low space reserve is missing. */
-
- extern pascal Ptr NewPermPtr(Size logicalSize);
- /* Allocates a permanent Pointer; you should call this instead of NewPointer if allocating
- some permanent memory. */
-
- extern pascal Handle NewPermHandle(Size logicalSize);
- /* Allocates a permanent handle; you should call this instead of NewHandle if allocating
- some
- permanent memory. */
-
- extern pascal Boolean PermAllocation(Boolean permanent);
- /* PermAllocation controls whether subsequent memory allocations are considered permanent or
- temporary.Pass TRUE to setup things for a permanent allocation.Returns the previous state
- of the permanent flag. */
-
- extern pascal void SetPermHandleSize(Handle h, Size newSize);
- /* Use this call to size permanent handles. It sets/resets the permanent flag correctly and
- does a FailMemError. */
-
- extern pascal void SetPermPtrSize(Ptr p, Size newSize);
- /* Use this call to size permanent pointers. It sets/resets the permanent flag correctly and
- does a FailMemError. */
-
- extern pascal void SetReserveSize(Size forCode, Size forOther);
- /* Call this to set the size of the memory reserved for code (temporary) and permanent (low
- memory) requests. */
-
- extern pascal Size TotalTempSize(Boolean justLocked, Handle *canPurge);
- /* TotalTempSize returns the total number of bytes of the temporary handles currently in RAM
- (or only locked/in use handles if justLocked is TRUE). CanPurge is set to an unlocked
- handle that can be purged if desired. Uses ScanHandles. */
-
- #if qDebug
-
- extern pascal void WriteReserves(void);
- /* WRITELN's the temporary reserve and low-memory reserves in the debug window. */
- #endif
-
- /* U T I L I T I E S */
-
- extern pascal Size AddSegSizes(Handle segRsrc);
- /* Returns the total size of the code segments whose names are in the string list segRrs
- c. */
-
- extern pascal void SetStackSpace(Size numBytes);
- /* Set the stack space to at least numBytes. */
- #endif
-
- extern pascal void WithCodeResFileDo(pascal void (*DoWithResFile)(void *DoWithResFile_StaticLink),
- void *DoWithResFile_StaticLink);
- /* Ensure that the resource call is done against gCodeRefNum */
-
-